local table = table
local string = string
local pairs = pairs
local type = type
Counter = Counter or {}

-- start table
-- 递归的最大深度
local MAX_RECURSION_DEPTH = 100

--[[
    获取对象的格式化文本显示
    @param object any       要格式化的对象
    @param pretty boolean   是否使用缩进来格式化输出内容
    @param depth  number    当前递归深度，用以防止死递归，pretty为true时也用以计算缩进数量，通常不需要手动传入
    @return       string    格式化后的字符串
]]
function table.dump(object, pretty, depth)
    depth = depth or 1
    if depth > MAX_RECURSION_DEPTH then
        error("table.dump: too deep")
    end

    local nextDepth = depth + 1
    local objType = type(object)
    if type(object) == "string" then
        return string.format("%q", object)
    end

    if type(object) ~= 'table' then
        return tostring(object)
    end

    local formatIndent = "\n" .. string.rep("  ", depth)
    local result = {'{'}
    for k, v in pairs(object) do
        table.insert(result, string.format("%s[%s] = %s,", pretty and formatIndent or "", table.dump(k),
            table.dump(v, pretty, nextDepth)))
    end

    table.insert(result, pretty and formatIndent or "")
    table.insert(result, '}')
    return table.concat(result)
end

function table.index(t, val)
    for k, v in pairs(t) do
        if v == val then
            return k
        end
    end
end

function table.islist(t)
    if type(t) ~= "table" then
        return false
    end

    for k in pairs(t) do
        if type(k) ~= "number" or k < 1 or k > #t then
            return false
        end
    end

    return true
end

-- 将表的字符串表示转换为表，对于 table.dump(obj) 来说，当 obj 是一个只由字符串和数字组成的表时，它们是互逆的
function table.undump(str)
    return assert(load("return " .. str))()
end

function table.length(tbl)
    local length = 0
    for _ in pairs(tbl) do
        length = length + 1
    end

    return length
end

function table.group(tbl, keyOrFunc)
    local result = {}
    local isKey = type(keyOrFunc) == "string"
    for k, v in pairs(tbl) do
        local key = isKey and keyOrFunc or keyOrFunc(v, k)
        if key ~= nil then
            if not result[key] then
                result[key] = {}
            end

            table.insert(result[key], v)
        end
    end

    return result
end

function table.copy(tbl)
    local result = {}
    for k, v in pairs(tbl) do
        result[k] = v
    end

    return result
end

-- 深度复制
function table.deepcopy(tbl)
    local result = {}
    for k, v in pairs(tbl) do
        if type(v) == "table" then
            result[k] = table.deepcopy(v)
        else
            result[k] = v
        end
    end

    return result
end

-- 内容相等性判断
function table.equal(tbl1, tbl2, depth)
    depth = depth or 1
    if depth > MAX_RECURSION_DEPTH then
        error("table.equal: too deep")
    end

    if tbl1 == tbl2 then
        return true
    end

    local type1 = type(tbl1)
    local type2 = type(tbl2)
    if type1 ~= type2 or type1 ~= "table" then
        return false
    end

    for k, v in pairs(tbl1) do
        if not table.equal(v, tbl2[k], depth + 1) then
            return false
        end
    end

    for k, v in pairs(tbl2) do
        if not table.equal(v, tbl1[k], depth + 1) then
            return false
        end
    end

    return true
end

function table.keys(tbl)
    local result = {}
    for key in pairs(tbl) do
        table.insert(result, key)
    end

    return result
end

function table.values(tbl)
    local result = {}
    for _, v in pairs(tbl) do
        table.insert(result, v)
    end

    return result
end

function table.contain(tbl, value)
    for _, v in pairs(tbl) do
        if v == value then
            return true
        end
    end

    return false
end

-- 表中是否包含一个表内容相同的表
function table.containtbl(tbl, vtbl)
    for _, v in pairs(tbl) do
        if table.equal(v, vtbl) then
            return true
        end
    end

    return false
end

function table.empty(tbl)
    return next(tbl) == nil
end

function table.column(list, vkey, kkey)
    local result = {}
    if not kkey then
        for k, v in pairs(list) do
            table.insert(result, v[vkey])
        end

        return result
    end

    for k, v in pairs(list) do
        result[v[kkey]] = vkey and v[vkey] or v
    end

    return result
end

-- 反转表的 key 和 value
function table.flip(tbl)
    local result = {}
    for k, v in pairs(tbl) do
        result[v] = k
    end

    return result
end

-- 去除表中的第一个元素并返回之
function table.shift(list)
    return table.remove(list, 1)
end

-- 在表最前面插入一个元素
function table.unshift(list, value)
    return table.insert(list, 1, value)
end

function table.except(tbl, val)
    local result = {}
    for k, v in pairs(tbl) do
        if v ~= val then
            result[k] = v
        end
    end

    return result
end

-- 合并 table，相同的 key，后面的 table 会覆盖前面的
function table.merge(...)
    local tbls = {...}

    local result = {}
    for i = 1, #tbls do
        local tbl = tbls[i]
        for key, value in pairs(tbl) do
            result[key] = value
        end
    end

    return result
end

-- 获取表中最大数字索引，用于产生一个可以包含 nil 的列表
function table.maxidx(list)
    local maxidx = 0
    for idx in pairs(list) do
        if idx > maxidx then
            maxidx = idx
        end
    end

    return maxidx
end

-- 遍历表以生成一个新的表
function table.map(tbl, func)
    local result = {}
    for k, v in pairs(tbl) do
        result[k] = func(v, k, tbl)
    end

    return result
end

--- 获取值在表中的位置，如果找不到，返回 nil
function table.pos(tbl, v)
    for idx, value in pairs(tbl) do
        if value == v then
            return idx
        end
    end
end

-- 遍历表以执行函数
function table.foreach(tbl, func)
    for k, v in pairs(tbl) do
        func(v, k, tbl)
    end
end

function table.slice(list, first, last)
    last = last or #list

    local result = {}
    for i = first, last do
        table.insert(result, list[i])
    end

    return result
end

-- 清除列表中的 hole(洞)
function table.clearhole(list)
    local maxid = table.maxidx(list)
    local result = {}
    for i = 1, maxid do
        if list[i] ~= nil then
            table.insert(result, list[i])
        end
    end

    return result
end

-- 对表进行过滤，将 func(v,k) 返回为假值(nil 或 false)的key-value对剔除
-- 如果传入一个 list，函数会保证原来的 key-value 对顺序不变，也就是说，他通常不会返回一个 list
function table.filter(tbl, func)
    local result = {}
    for k, v in pairs(tbl) do
        if func(v, k) then
            result[k] = v
        end
    end

    return result
end

-- 同 table.filter, 但是会保证返回的是一个 list
---@param list table 要过滤的 list
function table.filterlist(list, func)
    local result = {}
    for k, v in pairs(list) do
        if func(v, k) then
            table.insert(result, v)
        end
    end

    return result
end

---@param list table 要排序的列表
---@param inplace boolean 是否就地随机排序,如果为 true，则原列表会被修改, 默认为 false
---@return table result 排序后的列表，如果是就地排序，这个表就是原列表
function table.shuffle(list, inplace)
    local count = #list
    local result = inplace and list or table.copy(list)
    for i = 1, count do
        local j = math.random(i)
        result[i], result[j] = result[j], result[i]
    end

    return result
end

-- 列表去重
function table.unique(list)
    local result = {}
    for i = 1, #list do
        result[list[i]] = true
    end

    return table.keys(result)
end

-- 集合差集
function table.diff(list1, list2)
    local result = {}
    for i = 1, #list1 do
        local v = list1[i]
        if not table.contain(list2, v) then
            table.insert(result, v)
        end
    end

    return result
end

-- 集合交集
function table.intersect(...)
    local lists = {...}

    local result = {}
    for i = 1, #lists do
        local list = lists[i]
        for j = 1, #list do
            table.insert(result, list[j])
        end
    end

    return result
end

-- 集合并集
function table.union(...)
    local lists = {...}

    local result = {}
    for i = 1, #lists do
        local list = lists[i]
        for j = 1, #list do
            if not table.contain(result, list[j]) then
                table.insert(result, list[j])
            end
        end
    end

    return result
end
-- end table

-- start string
function string.empty(str)
    return str == nil or #str == 0
end

function string.startwith(str, prefix)
    return string.sub(str, 1, #prefix) == prefix
end

function string.endwith(str, suffix)
    return string.sub(str, -#suffix) == suffix
end

-- end string

-- start Counter
--- 判断数字是否在指定范围内
---@param num number 需要效验的数字
---@param min number 最小值(包含)
---@param max number 最大值(包含)
function Counter.between(num, min, max)
    return num >= min and num <= max
end

function Counter.notBetween(num, min, max)
    return not Counter.between(num, min, max)
end
-- end Counter

-- start io
function io.exists(filename)
    local file = io.open(filename, "r")
    if file then
        io.close(file)
        return true
    end

    return false
end

-- end io
